#!/usr/bin/env python
# -*- coding:utf8 -*-
"""
Author : mafei
@Date   : 2019/12/02

"""

import json

from django.http import HttpRequest

DEFAULT_VALUE = '__default_value__'


class UException(Exception):
    pass


class NotJsonFormatBody(UException):
    '''
    request body 不是 json 格式
    '''


class InvalidParameter(UException):
    '''
    非法的参数 - 用于 bget*, qget* 方法
    '''


def qget_int(self, name, default=DEFAULT_VALUE, error_msg=None):
    '''
    从 query string 中获取一个整型参数
    '''
    request_data = self.GET
    if name in request_data:
        value = request_data.get(name)
        if isinstance(value, basestring):
            if not value.isdigit():
                raise InvalidParameter(u'参数 %s 必须为整型' % name)
            value = int(value)
        elif not isinstance(value, int):
            raise InvalidParameter(u'参数 %s 必须为整型' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def qget_float(self, name, default=DEFAULT_VALUE, error_msg=None):
    '''
    从 query string 中获取一个浮点型参数
    '''
    request_data = self.GET
    if name in request_data:
        value = request_data.get(name)
        if isinstance(value, basestring):
            try:
                value = float(value)
            except ValueError:
                raise InvalidParameter(u'参数 %s 必须为浮点型' % name)
        elif not isinstance(value, (int, float)):
            raise InvalidParameter(u'参数 %s 必须为浮点型' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def qget_bool(self, name, default=DEFAULT_VALUE, not_exist_for_false=True, exist_without_value_for_true=True,
              error_msg=None):
    '''
    从 query string 中获取一个布尔型参数
    :param self: request 实例
    :param name: 参数名称
    :param default: 默认值
    :param not_exist_for_false: 参数不存在且未指定默认值的时候是返回 false还是抛异常, 默认返回false
    :param exist_without_value_for_true: 参数存在但是没有值返回true还是false, 默认是 true
    :param error_msg: 自定义的错误信息
    :return:
    '''
    request_data = self.GET
    if name in request_data:
        value = request_data.get(name, '')
        if not value and exist_without_value_for_true:
            return True
        if value.lower() in ('1', 'true', 'yes', 'ok'):
            return True
        elif value.lower() in ('0', 'false', 'no'):
            return False
        else:
            raise InvalidParameter(error_msg or u'参数 %s 必须为 (1, 0, true, false, yes, no) 之一' % name)
    else:
        if default is not DEFAULT_VALUE:
            return default
        elif not_exist_for_false:
            return False
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def qget_string(self, name, default=DEFAULT_VALUE, allow_empty=False, error_msg=None):
    '''
    从 query string 中获取一个字符串参数
    '''
    request_data = self.GET
    if name in request_data:
        value = request_data.get(name)
        if not isinstance(value, basestring):
            raise InvalidParameter(error_msg or u'参数 %s 必须为字符串' % name)
        if not allow_empty and not value:
            raise InvalidParameter(u'参数 %s 不能为空' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


#################################################

def bget_int(self, name, default=DEFAULT_VALUE, error_msg=None):
    '''
    从 post body 中获取一个整型参数
    '''
    request_data = self.request_data
    if name in request_data:
        value = request_data.get(name)
        if isinstance(value, basestring):
            if not value.isdigit():
                raise InvalidParameter(u'参数 %s 必须为整型' % name)
            value = int(value)
        elif not isinstance(value, int):
            raise InvalidParameter(u'参数 %s 必须为整型' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def bget_float(self, name, default=DEFAULT_VALUE, error_msg=None):
    '''
    从 post body 中获取一个浮点型参数
    '''
    request_data = self.request_data
    if name in request_data:
        value = request_data.get(name)
        if isinstance(value, basestring):
            try:
                value = float(value)
            except ValueError:
                raise InvalidParameter(u'参数 %s 必须为浮点型' % name)
        elif not isinstance(value, (int, float)):
            raise InvalidParameter(u'参数 %s 必须为浮点型' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def bget_bool(self, name, default=DEFAULT_VALUE, error_msg=None):
    '''
    从 post body 中获取一个布尔型参数
    '''
    request_data = self.request_data
    if name in request_data:
        value = request_data.get(name)
        if not isinstance(value, bool):
            raise InvalidParameter(error_msg or u'参数 %s 必须为布尔型' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def bget_string(self, name, default=DEFAULT_VALUE, error_msg=None):
    '''
    从 post body 中获取一个字符串参数
    '''
    request_data = self.request_data
    if name in request_data:
        value = request_data.get(name)
        if not isinstance(value, basestring):
            raise InvalidParameter(error_msg or u'参数 %s 必须为字符串' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def bget_list(self, name, default=DEFAULT_VALUE, error_msg=None, allow_empty=True):
    '''
    从 post body 中获取一个列表参数
    '''
    request_data = self.request_data
    if name in request_data:
        value = request_data.get(name)
        if isinstance(value, basestring):
            try:
                value = json.loads(value)
                if not isinstance(value, list):
                    raise InvalidParameter(u'参数 %s 必须为列表' % name)
            except ValueError:
                raise InvalidParameter(u'参数 %s 必须为列表' % name)
        elif not isinstance(value, list):
            raise InvalidParameter(u'参数 %s 必须为列表' % name)
        if not allow_empty and not value:
            raise InvalidParameter(u'参数 %s 不能为空' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def bget_dict(self, name, default=DEFAULT_VALUE, error_msg=None, allow_empty=True):
    '''
    从 post body 中获取一个字典参数
    '''
    request_data = self.request_data
    if name in request_data:
        value = request_data.get(name)
        if isinstance(value, basestring):
            try:
                value = json.loads(value)
                if not isinstance(value, dict):
                    raise InvalidParameter(error_msg or u'参数 %s 必须为字典' % name)
            except ValueError:
                raise InvalidParameter(error_msg or u'参数 %s 必须为字典' % name)
        elif not isinstance(value, dict):
            raise InvalidParameter(error_msg or u'参数 %s 必须为字典' % name)
        if not allow_empty and not value:
            raise InvalidParameter(error_msg or u'参数 %s 不能为空' % name)
        return value
    else:
        if default is not DEFAULT_VALUE:
            return default
        else:
            raise InvalidParameter(error_msg or u'参数 %s 未提供' % name)


def client_ip(self):
    if 'HTTP_X_FORWARDED_FOR' in self.META:
        return self.META['HTTP_X_FORWARDED_FOR'].split(",")[0].strip()
    elif 'HTTP_X_REAL_IP' in self.META:
        return self.META['HTTP_X_REAL_IP']
    elif 'REMOTE_ADDR' in self.META:
        return self.META['REMOTE_ADDR']
    else:
        return 'ip-not-found'


def query_data(self):
    '''
    querystring 中的参数
    :param self:
    :return:
    '''
    return self.GET


def request_data(self):
    '''
    request body 中的参数
    :param self:
    :return:
    '''
    body = self.body
    try:
        if body:
            post_data = json.loads(body)
        else:
            post_data = {}
    except ValueError:
        raise NotJsonFormatBody()
    if not isinstance(post_data, (list, dict)):
        raise NotJsonFormatBody()

    return post_data


def query_dict(self):
    '''
    为了兼容
    :param self:
    :return:
    '''
    if self.method == 'GET':
        return self.query_data
    else:
        return self.request_data


def debug_enabled(self):
    if self.META.get('HTTP_LBDEBUG', '').lower() in ('yes', 'true'):
        return True
    return False


def extend_request():
    HttpRequest.query_dict = property(query_dict)  # 兼容
    HttpRequest.query_data = property(query_data)  # QueryString Object
    HttpRequest.request_data = property(request_data)  # Request Body Object
    HttpRequest.client_ip = property(client_ip)

    # 从 querystring 中获取数据
    HttpRequest.qget_int = qget_int
    HttpRequest.qget_float = qget_float
    HttpRequest.qget_bool = qget_bool
    HttpRequest.qget_string = qget_string

    # 从 request body 中获取数据
    HttpRequest.bget_int = bget_int
    HttpRequest.bget_float = bget_float
    HttpRequest.bget_bool = bget_bool
    HttpRequest.bget_string = bget_string
    HttpRequest.bget_list = bget_list
    HttpRequest.bget_dict = bget_dict

    # for debug
    HttpRequest.debug_enabled = property(debug_enabled)
